package com.obrock;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

/**
 * Created with IntelliJ IDEA.
 * User: Rick
 * Date: 07.10.12
 * Time: 10:25
 * To change this template use File | Settings | File Templates.
 */
public class MessageTemplate {
    public static final int DIRECTION_IN = 0;
    public static final int DIRECTION_OUT = 1;

    public String title = "";
    public String card = "XXXXXXXXXXXXXXXX";
    public Date date = new Date();
    public double amount = 0.0;
    public double balance = 0.0;
    public double foreign = 0.0;
    public double course = 0.0;
    public String currency = "";
    public String key = "";

    public String template = "";

    public MessageTemplate(String tmp) {
        template = tmp;
    }

    private String cell(String src, String n) {
        if (n == null) {
            return src;
        } else {
            int pos = src.indexOf(n);
            if (pos < 0) return null;
            return src.substring(0, pos);
        }
    }

    private String digi(String src, String n) {
        if (n == null) {
            return src;
        } else {
            String dst = "";
            for (int pos = 0; pos < src.length(); ++pos) {
                char c = src.charAt(pos);
                if (Character.isDigit(c)) {
                    dst += c;
                } else if (c == ' ') {
                    if (pos < src.length() && Character.isDigit(src.charAt(pos + 1))) {
                        dst += c;
                    } else {
                        break;
                    }
                } else if (c == '-') {
                    if (pos == 0) {
                        dst += c;
                    } else {
                        break;
                    }
                } else if (c == '.' || c == ',') {
                    String tmp = cell(src.substring(pos), n);
                    if (tmp == null) {
                        return null;
                    }
                    dst += tmp;
                    break;
                }
            }
            return dst;
        }
    }

    private boolean isUnique(String[] struct, int pos) {
        int cnt = 0;
        for (String s : struct) {
            if (s.contains(struct[pos])) {
                ++cnt;
            }
        }
        return cnt == 1;
    }

    public boolean parse(String src) {
        String[] struct = template.split("%");
        if(struct[0].length() == 0 && !template.startsWith("%%")) {
            struct = Arrays.copyOfRange(struct,1,struct.length-1);
        }
        if(struct.length > 1 && struct[struct.length-1].length() == 0 && !template.endsWith("%%")) {
            struct = Arrays.copyOfRange(struct,0,struct.length-2);
        }

        int[] start = new int[struct.length];
        int[] stop = new int[struct.length];
        for (int i = 0; i < struct.length; ++i) {
            start[i] = -1;
            stop[i] = -1;
        }

        // нейтрализуем константы
        for (int i = 0; i < struct.length; ++i) {
            String s = struct[i];
            if (s.startsWith("DATE=")) {
            } else if (s.startsWith("CARD=")) {
            } else if (s.startsWith("AMOUNT")) {
            } else if (s.startsWith("BALANCE")) {
            } else if (s.startsWith("CURRENCY")) {
            } else if (s.startsWith("TITLE")) {
            } else if (s.startsWith("KEY")) {
            } else if (s.startsWith("IGNORE")) {
            } else if (s.startsWith("FOREIGN")) {
            } else if (s.startsWith("COURSE")) {
            } else if (s.trim().length() > 0 && isUnique(struct, i)) {
                int p = src.indexOf(s);
                if (p == -1) {
                    return false;
                }
                start[i] = p;
                stop[i] = p + s.length();
            }
        }

        boolean occur = false;
        do {
            occur = false;

            // корректируем соседние ячейки
            for (int i = 0; i < struct.length; ++i) {
                if (start[i] == -1 && i > 0 && stop[i - 1] != -1) {
                    start[i] = stop[i - 1];
                    occur = true;
                }
                if (stop[i] == -1 && i + 1 < struct.length && start[i + 1] != -1) {
                    stop[i] = start[i + 1];
                    occur = true;
                }
            }

            // корректируем ячейки с известной длиной
            for (int i = 0; i < struct.length; ++i) {
                String s = struct[i];
                if ((start[i] != -1 && stop[i] == -1) || (stop[i] != -1 && start[i] == -1)) {
                    if (s.startsWith("DATE=")) {
                        if (stop[i] == -1) {
                            stop[i] = start[i] + s.split("=")[1].length();
                            occur = true;
                        } else {
                            start[i] = stop[i] - s.split("=")[1].length();
                            occur = true;
                        }
                    } else if (s.startsWith("CARD=")) {
                        String val = s.split("=")[1];
                        char where = val.charAt(0);
                        int len = 0;
                        val = val.substring(1);
                        try {
                            switch (where) {
                                case 'M':
                                    len = Integer.parseInt(val.split(",")[1]);
                                    break;
                                case 'L':
                                case 'R':
                                    len = Integer.parseInt(val);
                                    break;
                            }
                        } catch (Exception e) {
                            return false;
                        }
                        if (stop[i] == -1) {
                            stop[i] = start[i] + len;
                            occur = true;
                        } else {
                            start[i] = stop[i] - len;
                            occur = true;
                        }
                    } else if (s.startsWith("KEY")) {
                        if (s.split("=").length > 1) {
                            String val = s.split("=")[1];
                            if (val.length() > 0) {
                                int len = 0;
                                try {
                                    len = Integer.parseInt(val);
                                } catch (Exception e) {
                                    return false;
                                }
                                if (stop[i] == -1) {
                                    stop[i] = start[i] + len;
                                    occur = true;
                                } else {
                                    start[i] = stop[i] - len;
                                    occur = true;
                                }
                            }
                        }
                    } else if (s.startsWith("TITLE")) {
                        if (s.split("=").length > 1) {
                            String val = s.split("=")[1];
                            if (val.length() > 0) {
                                int len = 0;
                                try {
                                    len = Integer.parseInt(val);
                                } catch (Exception e) {
                                    return false;
                                }
                                if (stop[i] == -1) {
                                    stop[i] = start[i] + len;
                                    occur = true;
                                } else {
                                    start[i] = stop[i] - len;
                                    occur = true;
                                }
                            }
                        }
                    } else if (s.startsWith("IGNORE")) {
                        if (s.split("=").length > 1) {
                            String val = s.split("=")[1];
                            if (val.length() > 0) {
                                int len = 0;
                                try {
                                    len = Integer.parseInt(val);
                                } catch (Exception e) {
                                    return false;
                                }
                                if (stop[i] == -1) {
                                    stop[i] = start[i] + len;
                                    occur = true;
                                } else {
                                    start[i] = stop[i] - len;
                                    occur = true;
                                }
                            }
                        }
                    } else if (s.startsWith("CURRENCY")) {
                        int len = 0;
                        if (s.split("=").length > 1) {
                            String val = s.split("=")[1];
                            if (val.length() > 0) {
                                try {
                                    len = Integer.parseInt(val);
                                } catch (Exception e) {
                                    return false;
                                }
                            }
                        } else {
                            len = 3;
                        }
                        if (stop[i] == -1) {
                            stop[i] = start[i] + len;
                            occur = true;
                        } else {
                            start[i] = stop[i] - len;
                            occur = true;
                        }
                    } else if (s.startsWith("AMOUNT")
                            || s.startsWith("BALANCE")
                            || s.startsWith("FOREIGN")
                            || s.startsWith("COURSE")) {
                        if (start[i] != -1 && stop[i] == -1) {
                            String n = i + 1 < struct.length ? struct[i + 1] : null;
                            String c = digi(src.substring(start[i]), n);
                            if (c == null) {
                                return false;
                            }
                            if (stop[i] == -1) {
                                stop[i] = start[i] + c.length();
                                occur = true;
                            } else {
                                start[i] = stop[i] - c.length();
                                occur = true;
                            }
                        }
                    } else if (s.length() == 0) {
                        if (stop[i] == -1) {
                            stop[i] = start[i] + 1;
                            occur = true;
                        } else {
                            start[i] = stop[i] - 1;
                            occur = true;
                        }
                    }
                }
            }

            // корректируем соседние ячейки
            for (int i = 0; i < struct.length; ++i) {
                if (start[i] == -1 && i > 0 && stop[i - 1] != -1) {
                    start[i] = stop[i - 1];
                    occur = true;
                }
                if (stop[i] == -1 && i + 1 < struct.length && start[i + 1] != -1) {
                    stop[i] = start[i + 1];
                    occur = true;
                }
            }

            // нейтрализуем пробелы
            for (int i = 0; i < struct.length; ++i) {
                if ((start[i] != -1 && stop[i] == -1) || (stop[i] != -1 && start[i] == -1)) {
                    String s = struct[i];
                    if (s.startsWith("DATE=")) {
                    } else if (s.startsWith("CARD=")) {
                    } else if (s.startsWith("AMOUNT")) {
                    } else if (s.startsWith("BALANCE")) {
                    } else if (s.startsWith("CURRENCY")) {
                    } else if (s.startsWith("TITLE")) {
                    } else if (s.startsWith("KEY")) {
                    } else if (s.startsWith("IGNORE")) {
                    } else if (s.startsWith("FOREIGN")) {
                    } else if (s.startsWith("COURSE")) {
                    } else if (s.length() > 0) {
                        if (stop[i] == -1) {
                            stop[i] = start[i] + s.length();
                            occur = true;
                        } else {
                            start[i] = stop[i] - s.length();
                            occur = true;
                        }
                    }
                }
            }

        } while (occur);


        String o = src;
        int pos = 0;
        for (int i = 0; i < struct.length; ++i) {

            String s = struct[i];
            String n = i + 1 < struct.length ? struct[i + 1] : null;

            if (start[i] != -1 && stop[i] != -1) {
                o = src.substring(start[i], stop[i]);
                pos = start[i];
            } else if (start[i] != -1) {
                o = src.substring(start[i]);
                pos = start[i];
            } else if (stop[i] != -1) {
                o = src.substring(pos, stop[i]);
            } else {
                o = src.substring(pos);
            }

            if (s.startsWith("DATE=")) {
                String val = s.split("=")[1];
                SimpleDateFormat format = new SimpleDateFormat(val);

                String c = (stop[i] == -1) ? cell(o, n) : o;

                if (c == null) {
                    return false;
                }
                try {
                    date = format.parse(c);
                } catch (ParseException e) {
                    return false;
                }
                pos += c.length();

            } else if (s.startsWith("CARD=")) {
                String val = s.split("=")[1];
                char where = val.charAt(0);
                int p = -1;
                int len = 0;
                val = val.substring(1);
                try {
                    switch (where) {
                        case 'M':
                            p = Integer.parseInt(val.split(",")[0]);
                            len = Integer.parseInt(val.split(",")[1]);
                            break;
                        case 'L':
                            len = Integer.parseInt(val);
                            p = 0;
                            break;
                        case 'R':
                            len = Integer.parseInt(val);
                            p = card.length() - len;
                            break;
                    }
                } catch (Exception e) {
                    return false;
                }

                String c = (stop[i] == -1) ? cell(o, n) : o;
                if (c == null || c.length() != len) {
                    return false;
                }
                card = card.substring(0, p) + c + card.substring(p + len);
                pos += c.length();

            } else if (s.startsWith("AMOUNT")) {
                String c = (stop[i] == -1) ? digi(o, n) : o;
                if (c == null) {
                    return false;
                }
                try {
                    amount = Double.parseDouble(c.replace(" ", "").replace(",", "."));
                } catch (Exception e) {
                    return false;
                }
                pos += c.length();

            } else if (s.startsWith("BALANCE")) {
                String c = (stop[i] == -1) ? digi(o, n) : o;
                if (c == null) {
                    return false;
                }
                try {
                    balance = Double.parseDouble(c.replace(" ", "").replace(",", "."));
                } catch (Exception e) {
                    return false;
                }
                pos += c.length();

            } else if (s.startsWith("FOREIGN")) {
                String c = (stop[i] == -1) ? digi(o, n) : o;
                if (c == null) {
                    return false;
                }
                try {
                    balance = Double.parseDouble(c.replace(" ", "").replace(",", "."));
                } catch (Exception e) {
                    return false;
                }
                pos += c.length();

            } else if (s.startsWith("COURSE")) {
                String c = (stop[i] == -1) ? digi(o, n) : o;
                if (c == null) {
                    return false;
                }
                try {
                    balance = Double.parseDouble(c.replace(" ", "").replace(",", "."));
                } catch (Exception e) {
                    return false;
                }
                pos += c.length();

            } else if (s.startsWith("CURRENCY")) {
                int len = 0;
                String c = "";
                if (s.split("=").length > 1) {
                    String val = s.split("=")[1];
                    if (val.length() > 0) {
                        try {
                            len = Integer.parseInt(val);
                        } catch (Exception e) {
                            return false;
                        }
                    }
                } else {
                    len = 3;
                }
                currency = o.substring(0, len);
                pos += 3;

            } else if (s.startsWith("TITLE")) {
                String c = "";
                if (s.split("=").length > 1) {
                    String val = s.split("=")[1];
                    if (val.length() > 0) {
                        int len = 0;
                        try {
                            len = Integer.parseInt(val);
                        } catch (Exception e) {
                            return false;
                        }
                        c = o.substring(0, len);
                    }
                } else {
                    c = (stop[i] == -1) ? cell(o, n) : o;
                }
                if (c == null) {
                    return false;
                }
                if (title.length() > 0) {
                    title = title.trim() + ", " + c.trim();
                } else {
                    title = c;
                }
                pos += c.length();

            } else if (s.startsWith("KEY")) {
                String c = "";
                if (s.split("=").length > 1) {
                    String val = s.split("=")[1];
                    if (val.length() > 0) {
                        int len = 0;
                        try {
                            len = Integer.parseInt(val);
                        } catch (Exception e) {
                            return false;
                        }
                        c = o.substring(0, len);
                    }
                } else {
                    c = (stop[i] == -1) ? cell(o, n) : o;
                }
                if (c == null) {
                    return false;
                }
                key = c;
                pos += c.length();

            } else if (s.startsWith("IGNORE")) {
                String c = "";
                if (s.split("=").length > 1) {
                    String val = s.split("=")[1];
                    if (val.length() > 0) {
                        int len = 0;
                        try {
                            len = Integer.parseInt(val);
                        } catch (Exception e) {
                            return false;
                        }
                        c = o.substring(0, len);
                    }
                } else {
                    c = (stop[i] == -1) ? cell(o, n) : o;
                }
                if (c == null) {
                    return false;
                }
                pos += c.length();

            } else if (s.length() == 0) {
                if (o.charAt(0) == '%') {
                    pos += 1;
                } else {
                    return false;
                }
            } else {
                if (!o.startsWith(s)) {
                    return false;
                }
                pos += s.length();
            }
        }

        return true;
    }

}
